/* Includes ------------------------------------------------------------------*/
#include "dw_ahbdma.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/
/*! Parameter validity check for AHBDMA peripheral . */
#define IS_AHBDMA_PERIPHERAL(x) x==x


/*! Parameter validity check for AHBDMA channel . */
#define IS_AHBDMA_CHANNEL(ch) \
        (((ch) == AHBDMA_CH_0) || \
         ((ch) == AHBDMA_CH_1) || \
         ((ch) == AHBDMA_CH_2) || \
         ((ch) == AHBDMA_CH_3) || \
         ((ch) == AHBDMA_CH_4) || \
         ((ch) == AHBDMA_CH_5) || \
         ((ch) == AHBDMA_CH_6) || \
         ((ch) == AHBDMA_CH_7))

/*! Parameter validity check for AHBDMA interrupt mask . */
#define IS_AHBDMA_ITMASK(mask) \
        ((((mask)&AHBDMA_IT_TFR_MASK) != 0) || \
         (((mask)&AHBDMA_IT_BLOCK_MASK) != 0) || \
         (((mask)&AHBDMA_IT_SRCTRAN_MASK) != 0) || \
         (((mask)&AHBDMA_IT_DSTTRAN_MASK) != 0) || \
         (((mask)&AHBDMA_IT_ERR_MASK) != 0))

/*! Parameter validity check for AHBDMA peripheral IF mask . */
#define IS_AHBDMA_PERIP_IF(peripIF) \
        (((peripIF) == AHBDMA_IF_MEM) || \
         ((peripIF) == AHBDMA0_IF_DAC0) || \
         ((peripIF) == AHBDMA0_IF_DAC1) || \
         ((peripIF) == AHBDMA0_IF_SRPWM0) || \
         ((peripIF) == AHBDMA0_IF_SRPWM1) || \
         ((peripIF) == AHBDMA0_IF_SRPWM2) || \
         ((peripIF) == AHBDMA0_IF_SRPWM3) || \
         ((peripIF) == AHBDMA0_IF_ADC0_CH2) || \
         ((peripIF) == AHBDMA0_IF_ADC0_CH3) || \
         ((peripIF) == AHBDMA0_IF_ADC1_CH2) || \
         ((peripIF) == AHBDMA0_IF_ADC1_CH3) || \
         ((peripIF) == AHBDMA0_IF_ADC2_CH2) || \
         ((peripIF) == AHBDMA0_IF_ADC2_CH3) || \
         ((peripIF) == AHBDMA0_IF_ACMP0_A) || \
         ((peripIF) == AHBDMA0_IF_ACMP0_B) || \
         ((peripIF) == AHBDMA0_IF_ACMP1_A) || \
         ((peripIF) == AHBDMA0_IF_ACMP1_B) || \
         ((peripIF) == AHBDMA1_IF_REV0) || \
         ((peripIF) == AHBDMA1_IF_REV1) || \
         ((peripIF) == AHBDMA1_IF_ETIMER0) || \
         ((peripIF) == AHBDMA1_IF_ETIMER1) || \
         ((peripIF) == AHBDMA1_IF_ETIMER2) || \
         ((peripIF) == AHBDMA1_IF_ETIMER3) || \
         ((peripIF) == AHBDMA1_IF_ADC0_CH0) || \
         ((peripIF) == AHBDMA1_IF_ADC0_CH1) || \
         ((peripIF) == AHBDMA1_IF_ADC1_CH0) || \
         ((peripIF) == AHBDMA1_IF_ADC1_CH1) || \
         ((peripIF) == AHBDMA1_IF_ADC2_CH0) || \
         ((peripIF) == AHBDMA1_IF_ADC2_CH1) || \
         ((peripIF) == AHBDMA1_IF_ACMP2_A) || \
         ((peripIF) == AHBDMA1_IF_ACMP2_B) || \
         ((peripIF) == AHBDMA1_IF_ACMP3_A) || \
         ((peripIF) == AHBDMA1_IF_ACMP3_B))

#define AHBDMA_TIMEOUT              (1000000U)
#define AHBDMA_REG_WIDCH            (32U)
#define OFFSET(TYPE, MEMBER)    ((uint32_t)(&(((TYPE *)0)->MEMBER)))

#define AHBDMA_CH_CTL_INIT_VALUE    (0x200304801ULL)
#define AHBDMA_CH_CFG_INIT_VALUE    (0x400000EE0ULL)

/* check [ch] channel is enable or disable */
#define AHBDMA_CH_IS_ENABLE(ch)    (1U << ch)

/* ENABLE / DISABLE Channel*/
#define CH_ENABLE_WE_OFFSET     (0x101U)
#define CH_DISABLE_WE_OFFSET    (0x100U)
#define AHBDMA_CH_WE_ENABLE(ch)     (CH_ENABLE_WE_OFFSET << ch)
#define AHBDMA_CH_WE_DISABLE(ch)    (CH_DISABLE_WE_OFFSET << ch)

/* ENABLE / DISABLE IT Channel*/
#define CH_ENABLE_IT_WE_OFFSET     (0x101U)
#define CH_DISABLE_IT_WE_OFFSET    (0x100U)
#define AHBDMA_CH_IT_WE_ENABLE(ch)     (CH_ENABLE_IT_WE_OFFSET << ch)
#define AHBDMA_CH_IT_WE_DISABLE(ch)    (CH_DISABLE_IT_WE_OFFSET << ch)

/* CLEAR IT Channel*/
#define CH_CLEAR_IT_WE_OFFSET    (0x1U)
#define AHBDMA_CH_IT_CLEAR(ch)    (CH_CLEAR_IT_WE_OFFSET << ch)

/* SET / RESET IT MASK for Channel*/
#define CH_ACTIVE_IT_OFFSET            (0x1U)
#define AHBDMA_CH_IT_ACTIVE(ch)    (CH_ACTIVE_IT_OFFSET << ch)

#define MAX_GATHER_SCATTER_COUNT       (0xFFFFFU)
#define MAX_GATHER_SCATTER_INTERVAL    (0xFFFU)

/*! Parameter validity check for AHBDMA transfer size . */
#define IS_AHBDMA_TR_SIZE(size)    ((size) <= AHBDMA_MAX_BLOCK_TR_SIZE)

/*! Parameter validity check for AHBDMA transfer width . */
#define IS_AHBDMA_TR_WIDTH(width) \
        (((width) == AHBDMA_BITS_8) || ((width) == AHBDMA_BITS_16) || ((width) == AHBDMA_BITS_32))

/*! Parameter validity check for AHBDMA transfer direction . */
#define IS_AHBDMA_TR_DIRECTION(dir) \
        (((dir) == AHBDMA_INCREMENTAL) || ((dir) == AHBDMA_DECREMENTAL) || ((dir) == AHBDMA_FIXED))

/*! Parameter validity check for AHBDMA burst transfer items */
#define IS_AHBDMA_TR_BURST_ITERMS(items) \
        (((items) == AHBDMA_BURST_DATA_ITEMS_1) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_4) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_8) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_16) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_32) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_64) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_128) || \
         ((items) == AHBDMA_BURST_DATA_ITEMS_256))

/*! Parameter validity check for AHBDMA transfer type */
#define IS_AHBDMA_TR_TYPE(type) \
        (((type) == AHBDMA_MEM_TO_MEM) || \
         ((type) == AHBDMA_MEM_TO_PER) || \
         ((type) == AHBDMA_PER_TO_MEM) || \
         ((type) == AHBDMA_PER_TO_PER))

/*! Parameter validity check for AHBDMA transfer channel priority */
#define IS_AHBDMA_TR_PRIORITY(prior) \
        (((prior) == AHBDMA_CH_PRIORITY_0) || \
         ((prior) == AHBDMA_CH_PRIORITY_1) || \
         ((prior) == AHBDMA_CH_PRIORITY_2) || \
         ((prior) == AHBDMA_CH_PRIORITY_3) || \
         ((prior) == AHBDMA_CH_PRIORITY_4) || \
         ((prior) == AHBDMA_CH_PRIORITY_5) || \
         ((prior) == AHBDMA_CH_PRIORITY_6) || \
         ((prior) == AHBDMA_CH_PRIORITY_7))

/*! Parameter validity check for AHBDMA transfer fifo mode */
#define IS_AHBDMA_TR_FIFO_MODE(mode) \
        (((mode) == AHBDMA_FIFO_SINGLE) || ((mode) == AHBDMA_FIFO_HALF_DEPTH))

/*! Parameter validity check for AHBDMA multi transfer type */
#define IS_AHBDMA_MULTI_TR_TYPE(type) \
        (((type) == AHBDMA_CONTIGUOUS) || \
         ((type) == AHBDMA_RELOAD) || \
         ((type) == AHBDMA_LINKED_LIST))

/*! Parameter validity check for AHBDMA gather/scatter count */
#define IS_AHBDMA_GATHER_SCATTER_COUNT(count)          ((count) <= MAX_GATHER_SCATTER_COUNT)

/*! Parameter validity check for AHBDMA gather/scatter Interval */
#define IS_AHBDMA_GATHER_SCATTER_INTERVAL(interval)    ((interval) <= MAX_GATHER_SCATTER_INTERVAL)

/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/

/**
 * @brief Enable AHBDMA device
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return DRV_StatusTypeDef
 * DRV_OK: enable success or have been enabled
 */
DRV_StatusTypeDef AHBDMA_Enable(AHBDMA_TypeDef *AHBDMAx)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    /* avoid re-enabling AHBDMA device */
    if (READ_BIT(AHBDMAx->MISC.CFGREG, AHBDMA_MISC_CFG_Msk) != 0)
    {
        return DRV_OK;
    }

    SET_BIT(AHBDMAx->MISC.CFGREG, AHBDMA_MISC_CFG_Msk);
    return DRV_OK;
}

/**
 * @brief Disable AHBDMA device
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return DRV_StatusTypeDef
 * DRV_OK: disable success
 * DRV_TIMEOUT: disable failed because of DMA transfer dost not end during timeout time
 */
DRV_StatusTypeDef AHBDMA_Disable(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t timeout = AHBDMA_TIMEOUT;
    uint32_t i;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (i = 0; i < AHBDMA_NUM_CHANNELS; i++)
    {
        AHBDMA_ChDisable(AHBDMAx, i);
    }

    CLEAR_BIT(AHBDMAx->MISC.CFGREG, AHBDMA_MISC_CFG_Msk);
    while (timeout != 0U && (READ_BIT(AHBDMAx->MISC.CFGREG, AHBDMA_MISC_CFG_Msk) != 0))
    {
        timeout--;
    }

    if (timeout == 0)
    {
        return DRV_TIMEOUT;
    }

    return DRV_OK;
}

/**
 * @brief Enable channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @return DRV_StatusTypeDef
 * DRV_OK: enable success or have been enabled
 */
DRV_StatusTypeDef AHBDMA_ChEnable(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    /* avoid reenable, need a test */
    if ((READ_REG(AHBDMAx->MISC.CHENREG) & AHBDMA_CH_IS_ENABLE(ch)) != 0)
    {
        return DRV_OK;
    }

    WRITE_REG(AHBDMAx->MISC.CHENREG, AHBDMA_CH_WE_ENABLE(ch));
    return DRV_OK;
}

/**
 * @brief Disable channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @return DRV_StatusTypeDef
 * DRV_OK: disable success
 * DRV_TIMEOUT: disable failed because of DMA transfer dost not end during timeout time
 */
DRV_StatusTypeDef AHBDMA_ChDisable(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    uint32_t timeout = AHBDMA_TIMEOUT;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    WRITE_REG(AHBDMAx->MISC.CHENREG, AHBDMA_CH_WE_DISABLE(ch));
    while (timeout != 0 && (READ_REG(AHBDMAx->MISC.CHENREG) & AHBDMA_CH_IS_ENABLE(ch)) != 0)
    {
        timeout--;
    }

    if (timeout == 0)
    {
        return DRV_TIMEOUT;
    }

    return DRV_OK;
}

/**
 * @brief init channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param init: channel initialized parameter structure
 * @param ch: AHBDMA channel
 */
void AHBDMA_ChInit(AHBDMA_TypeDef *AHBDMAx, const AHBDMA_Ch_Init_TypeDef *init, uint32_t ch)
{
    uint64_t reg     = 0;
    uint32_t srcAddr = init->sar;
    uint32_t dstAddr = init->dar;
    uint32_t llpAddr = init->llp;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));
    assert_param(IS_AHBDMA_TR_SIZE(init->blkTfrSize));
    assert_param(IS_AHBDMA_TR_WIDTH(init->srcTrWidth));
    assert_param(IS_AHBDMA_TR_WIDTH(init->dstTrWidth));
    assert_param(IS_AHBDMA_TR_DIRECTION(init->srcAddressInc));
    assert_param(IS_AHBDMA_TR_DIRECTION(init->dstAddressInc));
    assert_param(IS_AHBDMA_TR_BURST_ITERMS(init->srcBurstDataItemsNum));
    assert_param(IS_AHBDMA_TR_BURST_ITERMS(init->dstBurstDataItemsNum));
    assert_param(IS_AHBDMA_TR_TYPE(init->tfrType));
    assert_param(IS_AHBDMA_TR_PRIORITY(init->prior));
    assert_param(IS_AHBDMA_TR_FIFO_MODE(init->fifoMode));
    assert_param(IS_AHBDMA_PERIP_IF(init->srcPer));
    assert_param(IS_AHBDMA_PERIP_IF(init->dstPer));
    assert_param(IS_AHBDMA_GATHER_SCATTER_INTERVAL(init->srcGatherInterval));
    assert_param(IS_AHBDMA_GATHER_SCATTER_COUNT(init->srcGatherCount));
    assert_param(IS_AHBDMA_GATHER_SCATTER_INTERVAL(init->dstScatterInterval));
    assert_param(IS_AHBDMA_GATHER_SCATTER_COUNT(init->dstScatterCount));


    WRITE_REG(AHBDMAx->CH[ch].SAR, srcAddr);
    WRITE_REG(AHBDMAx->CH[ch].DAR, dstAddr);
    WRITE_REG(AHBDMAx->CH[ch].LLP, llpAddr);

    reg = (uint64_t)init->srcTrWidth << AHBDMA_CR_SRC_TR_WIDTH_Pos |
          (uint64_t)init->dstTrWidth << AHBDMA_CR_DST_TR_WIDTH_Pos |
          (uint64_t)init->srcAddressInc << AHBDMA_CR_SINC_Pos |
          (uint64_t)init->dstAddressInc << AHBDMA_CR_DINC_Pos |
          (uint64_t)init->srcBurstDataItemsNum << AHBDMA_CR_SRC_MSIZE_Pos |
          (uint64_t)init->dstBurstDataItemsNum << AHBDMA_CR_DST_MSIZE_Pos |
          (uint64_t)init->srcGatherEn << AHBDMA_CR_SRC_GATHER_EN_Pos |
          (uint64_t)init->dstScatterEn << AHBDMA_CR_DST_SCATTER_EN_Pos |
          (uint64_t)init->tfrType << AHBDMA_CR_TT_FC_Pos |
          (uint64_t)init->dstLLPEn << AHBDMA_CR_LLP_DST_EN_Pos |
          (uint64_t)init->srcLLPEn << AHBDMA_CR_LLP_SRC_EN_Pos |
          (uint64_t)init->blkTfrSize << AHBDMA_CR_BLOCK_TS_Pos |
          (uint64_t)init->wbDoneEn << AHBDMA_CR_DONE_Pos;
    WRITE_REG(AHBDMAx->CH[ch].CTL, reg);

    reg = 0;
    reg = (uint64_t)init->prior << AHBDMA_CFG_CH_PRIOR_Pos |
          (uint64_t)init->srcReloadEn << AHBDMA_CFG_RELOAD_SRC_Pos |
          (uint64_t)init->dstReloadEn << AHBDMA_CFG_RELOAD_DST_Pos |
          (uint64_t)init->fifoMode << AHBDMA_CFG_FIFO_MODE_Pos |
          (uint64_t)init->srcPer << AHBDMA_CFG_SRC_PER_Pos |
          (uint64_t)init->dstPer << AHBDMA_CFG_DST_PER_Pos;
    WRITE_REG(AHBDMAx->CH[ch].CFG, reg);
    WRITE_REG(AHBDMAx->CH[ch].SGR, init->srcGatherCount << AHBDMA_SGR_SGC_Pos |
              init->srcGatherInterval << AHBDMA_SGR_SGI_Pos);
    WRITE_REG(AHBDMAx->CH[ch].DSR, init->dstScatterCount << AHBDMA_DSR_SGC_Pos |
              init->dstScatterInterval << AHBDMA_DSR_SGI_Pos);
}

/**
 * @brief Deinit channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @return DRV_StatusTypeDef
 * DRV_OK: deinit success
 * DRV_TIMEOUT: deinit failed because of DMA transfer dost not end during timeout time
 */
DRV_StatusTypeDef AHBDMA_ChDeInit(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    if (AHBDMA_ChDisable(AHBDMAx, ch) != DRV_OK)
    {
        return DRV_ERROR;
    }

    WRITE_REG(AHBDMAx->CH[ch].SAR, 0ULL);
    WRITE_REG(AHBDMAx->CH[ch].DAR, 0ULL);
    WRITE_REG(AHBDMAx->CH[ch].LLP, 0ULL);
    WRITE_REG(AHBDMAx->CH[ch].CTL, AHBDMA_CH_CTL_INIT_VALUE);
    WRITE_REG(AHBDMAx->CH[ch].CFG, AHBDMA_CH_CFG_INIT_VALUE);
    return DRV_OK;
}

/**
 * @brief Init the channel initial structure
 *
 * @param init: channel initialized parameter structure
 */
void AHBDMA_ChStructInit(AHBDMA_Ch_Init_TypeDef *init)
{
    init->sar                  = 0x0U;
    init->dar                  = 0x0U;
    init->srcTrWidth           = AHBDMA_BITS_8;
    init->dstTrWidth           = AHBDMA_BITS_8;
    init->srcAddressInc        = AHBDMA_INCREMENTAL;
    init->dstAddressInc        = AHBDMA_INCREMENTAL;
    init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    init->dstScatterEn         = DISABLE;
    init->srcGatherEn          = DISABLE;
    init->tfrType              = AHBDMA_PER_TO_PER;
    init->dstLLPEn             = DISABLE;
    init->srcLLPEn             = DISABLE;
    init->blkTfrSize           = 0x2U;
    init->wbDoneEn             = DISABLE;
    init->prior                = AHBDMA_CH_PRIORITY_7;
    init->srcReloadEn          = DISABLE;
    init->dstReloadEn          = DISABLE;
    init->fifoMode             = AHBDMA_FIFO_SINGLE;
    init->srcPer               = AHBDMA_IF_MEM;
    init->dstPer               = AHBDMA_IF_MEM;
    init->llp                  = 0x0U;
    init->srcGatherInterval    = 0x0U;
    init->srcGatherCount       = 0x0U;
    init->dstScatterInterval   = 0x0U;
    init->dstScatterCount      = 0x0U;
}

/**
 * @brief Suspend channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 */
void AHBDMA_ChSuspend(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    SET_BIT(AHBDMAx->CH[ch].CFG, AHBDMA_CFG_CH_SUSP_Msk);
}

/**
 * @brief Resume channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 */
void AHBDMA_ChResume(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    CLEAR_BIT(AHBDMAx->CH[ch].CFG, AHBDMA_CFG_CH_SUSP_Msk);
}

/**
 * @brief Find a free channel
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * AHBDMA_CH_ERR: No free channel
 * channel ID: The free channel ID
 */
uint32_t AHBDMA_FindFreeChannel(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t i;
    uint32_t ch = AHBDMA_CH_ERR;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (i = 0; i < AHBDMA_NUM_CHANNELS; i++)
    {
        if ((READ_REG(AHBDMAx->MISC.CHENREG) & AHBDMA_CH_IS_ENABLE(i)) == 0)
        {
            ch = i;
            break;
        }
    }

    return ch;
}

/**
 * @brief Return specified AXIDMA transfer channel is free or not
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AXIDMA transfer channel index
 * @return true: channel is under a transfer
 * @return false: channel is not initialized or have completed tansfer
 */
bool AHBDMA_IsChannelFree(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    if ((READ_REG(AHBDMAx->MISC.CHENREG) & AHBDMA_CH_IS_ENABLE(ch)) == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @brief Judge channel fifo is empty or not
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @return true: channel fifo is empty
 * @return false: channel fifo is not empty
 */
bool AHBDMA_IsChannelFifoEmpty(AHBDMA_TypeDef *AHBDMAx, uint32_t ch)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));

    return(READ_BIT(AHBDMAx->CH[ch].CFG, AHBDMA_CFG_FIFO_EMPTY_Msk) != 0);
}

/**
 * @brief Get default settings for m2m mode, single-block transmitting mode
 *
 * @param init: channel initialized parameter structure
 * @param srcAddress: source address
 * @param dstAddress: destionation address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_M2MDefaultSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                       uint32_t size)
{
    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_8;
    init->dstTrWidth = AHBDMA_BITS_8;

    init->srcAddressInc = AHBDMA_INCREMENTAL;
    init->dstAddressInc = AHBDMA_INCREMENTAL;

    if ((size >= 1) && (size <= 3))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
    }
    else if ((size >= 4) && (size <= 7))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    }
    else if ((size >= 8) && (size <= 15))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_8;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_8;
    }
    else if ((size >= 16) && (size <= 31))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_16;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_16;
    }
    else if ((size >= 32) && (size <= 63))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_32;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_32;
    }
    else if ((size >= 64) && (size <= 127))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_64;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_64;
    }
    else if ((size >= 128) && (size <= 255))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_128;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_128;
    }
    else
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_256;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_256;
    }

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;     //single BLOCK is not suitable
    init->tfrType      = AHBDMA_MEM_TO_MEM;
    init->dstLLPEn     = DISABLE;
    init->srcLLPEn     = DISABLE;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = DISABLE;

    init->prior              = AHBDMA_CH_PRIORITY_4;
    init->srcReloadEn        = DISABLE;
    init->dstReloadEn        = DISABLE;
    init->fifoMode           = AHBDMA_FIFO_SINGLE;
    init->srcPer             = AHBDMA_IF_MEM;
    init->dstPer             = AHBDMA_IF_MEM;
    init->llp                = 0U;
    init->srcGatherInterval  = 0x0U;
    init->srcGatherCount     = 0x0U;
    init->dstScatterInterval = 0x0U;
    init->dstScatterCount    = 0x0U;
    return DRV_OK;
}

/**
 * @brief Get default settings for m2p mode, single-block transmitting mode
 *
 * @param init: channel initialized parameter structure
 * @param srcAddress: source address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_M2PDefaultSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                       uint32_t size, uint8_t dstPeripIF)
{
    assert_param(IS_AHBDMA_PERIP_IF(dstPeripIF));

    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_32;
    init->dstTrWidth = AHBDMA_BITS_32;

    init->srcAddressInc = AHBDMA_INCREMENTAL;
    init->dstAddressInc = AHBDMA_FIXED;

    init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
    init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;     //single BLOCK is not suitable
    init->tfrType      = AHBDMA_MEM_TO_PER;
    init->dstLLPEn     = DISABLE;
    init->srcLLPEn     = DISABLE;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = DISABLE;

    init->prior              = AHBDMA_CH_PRIORITY_4;
    init->srcReloadEn        = DISABLE;
    init->dstReloadEn        = DISABLE;
    init->fifoMode           = AHBDMA_FIFO_SINGLE;
    init->srcPer             = AHBDMA_IF_MEM;
    init->dstPer             = dstPeripIF;
    init->llp                = 0U;
    init->srcGatherInterval  = 0x0U;
    init->srcGatherCount     = 0x0U;
    init->dstScatterInterval = 0x0U;
    init->dstScatterCount    = 0x0U;
    return DRV_OK;
}

/**
 * @brief Get default settings for p2m mode, single-block transmitting mode
 *
 * @param init: channel initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_P2MDefaultSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                       uint32_t size, uint8_t srcPeripIF)
{
    assert_param(IS_AHBDMA_PERIP_IF(srcPeripIF));

    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_16;
    init->dstTrWidth = AHBDMA_BITS_16;

    init->srcAddressInc = AHBDMA_FIXED;
    init->dstAddressInc = AHBDMA_INCREMENTAL;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_PER_TO_MEM;

    init->dstLLPEn   = DISABLE;
    init->srcLLPEn   = DISABLE;
    init->blkTfrSize = (uint16_t)size;
    init->wbDoneEn   = DISABLE;

    init->prior              = AHBDMA_CH_PRIORITY_4;
    init->srcReloadEn        = DISABLE;
    init->dstReloadEn        = DISABLE;
    init->fifoMode           = AHBDMA_FIFO_SINGLE;
    init->srcPer             = srcPeripIF;
    init->dstPer             = AHBDMA_IF_MEM;
    init->llp                = 0U;
    init->srcGatherInterval  = 0x0U;
    init->srcGatherCount     = 0x0U;
    init->dstScatterInterval = 0x0U;
    init->dstScatterCount    = 0x0U;
    return DRV_OK;
}

/**
 * @brief Get default settings for p2p mode, single-block transmitting mode
 *
 * @param init: channel initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_P2PDefaultSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                       uint32_t size, uint8_t srcPeripIF, uint8_t dstPeripIF)
{
    assert_param(IS_AHBDMA_PERIP_IF(srcPeripIF));
    assert_param(IS_AHBDMA_PERIP_IF(dstPeripIF));

    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_32;
    init->dstTrWidth = AHBDMA_BITS_32;

    init->srcAddressInc = AHBDMA_FIXED;
    init->dstAddressInc = AHBDMA_FIXED;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_PER_TO_PER;

    init->dstLLPEn   = DISABLE;
    init->srcLLPEn   = DISABLE;
    init->blkTfrSize = (uint16_t)size;
    init->wbDoneEn   = DISABLE;

    init->prior              = AHBDMA_CH_PRIORITY_4;
    init->srcReloadEn        = DISABLE;
    init->dstReloadEn        = DISABLE;
    init->fifoMode           = AHBDMA_FIFO_SINGLE;
    init->srcPer             = srcPeripIF;
    init->dstPer             = dstPeripIF;
    init->llp                = 0U;
    init->srcGatherInterval  = 0x0U;
    init->srcGatherCount     = 0x0U;
    init->dstScatterInterval = 0x0U;
    init->dstScatterCount    = 0x0U;
    return DRV_OK;
}

/**
 * @brief Multi-Block transfer parameter set
 *
 * @param init: channel initialized parameter structure
 * @param sarUpdateMethod: SAR register update metheod in multi transfer
 * @param darUpdateMethod: DAR register update metheod in multi transfer
 * @param llp: link-list pointer
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_INVALID: sarUpdateMethod and darUpdateMethod do match
 */
DRV_StatusTypeDef AHBDMA_MultiBlockSet(AHBDMA_Ch_Init_TypeDef *init, uint8_t sarUpdateMethod, uint8_t darUpdateMethod,
                                       uint32_t llp)
{
    assert_param(IS_AHBDMA_MULTI_TR_TYPE(sarUpdateMethod));
    assert_param(IS_AHBDMA_MULTI_TR_TYPE(darUpdateMethod));

    init->llp = (uint32_t)llp & AHBDMA_LLPR_LOC_Msk;

    if ((sarUpdateMethod == AHBDMA_CONTIGUOUS) && (darUpdateMethod == AHBDMA_CONTIGUOUS))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = DISABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_CONTIGUOUS) && (darUpdateMethod == AHBDMA_RELOAD))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = ENABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_RELOAD) && (darUpdateMethod == AHBDMA_CONTIGUOUS))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = ENABLE;
        init->dstReloadEn = DISABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_RELOAD) && (darUpdateMethod == AHBDMA_RELOAD))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = ENABLE;
        init->dstReloadEn = ENABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_CONTIGUOUS) && (darUpdateMethod == AHBDMA_LINKED_LIST))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = ENABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = DISABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_RELOAD) && (darUpdateMethod == AHBDMA_LINKED_LIST))
    {
        init->srcLLPEn    = DISABLE;
        init->dstLLPEn    = ENABLE;
        init->srcReloadEn = ENABLE;
        init->dstReloadEn = DISABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_LINKED_LIST) && (darUpdateMethod == AHBDMA_CONTIGUOUS))
    {
        init->srcLLPEn    = ENABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = DISABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_LINKED_LIST) && (darUpdateMethod == AHBDMA_RELOAD))
    {
        init->srcLLPEn    = ENABLE;
        init->dstLLPEn    = DISABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = ENABLE;
    }
    else if ((sarUpdateMethod == AHBDMA_LINKED_LIST) && (darUpdateMethod == AHBDMA_LINKED_LIST))
    {
        init->srcLLPEn    = ENABLE;
        init->dstLLPEn    = ENABLE;
        init->srcReloadEn = DISABLE;
        init->dstReloadEn = DISABLE;
    }
    else
    {
        return DRV_INVALID;
    }

    return DRV_OK;
}

/**
 * @brief Set source gather transfer parameter
 *
 * @param init: LLI initialized parameter structure
 * @param gatherInterval: source gather interval
 * @param gatherCount: source gather count
 * @param status: ENABLE or DISABLE source gather transfer
 */
void AHBDMA_SourceGatherSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t gatherInterval, uint32_t gatherCount,
                            ControlStatus status)
{
    assert_param(IS_AHBDMA_GATHER_SCATTER_INTERVAL(gatherInterval));
    assert_param(IS_AHBDMA_GATHER_SCATTER_COUNT(gatherCount));

    if (status == ENABLE)
    {
        init->srcGatherEn       = ENABLE;
        init->srcGatherCount    = gatherCount;
        init->srcGatherInterval = gatherInterval;
    }
    else
    {
        init->srcGatherEn       = DISABLE;
        init->srcGatherCount    = gatherCount;
        init->srcGatherInterval = gatherInterval;
    }
}

/**
 * @brief Set source gather transfer parameter
 *
 * @param init: LLI initialized parameter structure
 * @param gatherInterval: source gather interval
 * @param gatherCount: source gather count
 * @param status: ENABLE or DISABLE source gather transfer
 */
void AHBDMA_DestinationScatterSet(AHBDMA_Ch_Init_TypeDef *init, uint32_t scatterInterval,
                                  uint32_t scatterCount, ControlStatus status)
{
    assert_param(IS_AHBDMA_GATHER_SCATTER_INTERVAL(scatterInterval));
    assert_param(IS_AHBDMA_GATHER_SCATTER_COUNT(scatterCount));

    if (status == ENABLE)
    {
        init->dstScatterEn       = ENABLE;
        init->dstScatterCount    = scatterCount;
        init->dstScatterInterval = scatterInterval;
    }
    else
    {
        init->dstScatterEn       = DISABLE;
        init->dstScatterCount    = scatterCount;
        init->dstScatterInterval = scatterInterval;
    }
}

/**
 * @brief Init LLI initial structure
 *
 * @param init: LLI initialized parameter structure
 */
void AHBDMA_LLI_StructInit(AHBDMA_LLI_Init_TypeDef *init)
{
    init->sar                  = 0x0U;
    init->dar                  = 0x0U;
    init->intEn                = ENABLE;
    init->srcTrWidth           = AHBDMA_BITS_8;
    init->dstTrWidth           = AHBDMA_BITS_8;
    init->srcAddressInc        = AHBDMA_INCREMENTAL;
    init->dstAddressInc        = AHBDMA_INCREMENTAL;
    init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    init->dstScatterEn         = DISABLE;
    init->srcGatherEn          = DISABLE;
    init->tfrType              = AHBDMA_PER_TO_PER;
    init->dstLLPEn             = DISABLE;
    init->srcLLPEn             = DISABLE;
    init->blkTfrSize           = 0x2U;
    init->wbDoneEn             = DISABLE;
}

/**
 * @brief Init LINK-LIST item
 *
 * @param init: LLI initialized parameter structure
 * @param lli: Pointer to link-list item
 */
void AHBDMA_LLI_Init(AHBDMA_LLI_TypeDef *lli, const AHBDMA_LLI_Init_TypeDef *init, bool isLastLLI, uint32_t nextLLP)
{
    uint32_t      reg            = 0;
    uint32_t      srcAddr        = init->sar;
    uint32_t      dstAddr        = init->dar;
    ControlStatus srcLLPEnStatus = init->srcLLPEn;
    ControlStatus dstLLPEnStatus = init->dstLLPEn;

    assert_param(IS_AHBDMA_TR_SIZE(init->blkTfrSize));
    assert_param(IS_AHBDMA_TR_WIDTH(init->srcTrWidth));
    assert_param(IS_AHBDMA_TR_WIDTH(init->dstTrWidth));
    assert_param(IS_AHBDMA_TR_DIRECTION(init->srcAddressInc));
    assert_param(IS_AHBDMA_TR_DIRECTION(init->dstAddressInc));
    assert_param(IS_AHBDMA_TR_BURST_ITERMS(init->srcBurstDataItemsNum));
    assert_param(IS_AHBDMA_TR_BURST_ITERMS(init->dstBurstDataItemsNum));
    assert_param(IS_AHBDMA_TR_TYPE(init->tfrType));

    lli->SAR = srcAddr;
    lli->DAR = dstAddr;

    if (isLastLLI != true)
    {
        lli->LLP = nextLLP & AHBDMA_LLPR_LOC_Msk;
    }
    else
    {
        srcLLPEnStatus = DISABLE;
        dstLLPEnStatus = DISABLE;
        lli->LLP       = 0U;
    }

    reg = (uint32_t)init->intEn << AHBDMA_CR_INT_EN_Pos |
          (uint32_t)init->srcTrWidth << AHBDMA_CR_SRC_TR_WIDTH_Pos |
          (uint32_t)init->dstTrWidth << AHBDMA_CR_DST_TR_WIDTH_Pos |
          (uint32_t)init->srcAddressInc << AHBDMA_CR_SINC_Pos |
          (uint32_t)init->dstAddressInc << AHBDMA_CR_DINC_Pos |
          (uint32_t)init->srcBurstDataItemsNum << AHBDMA_CR_SRC_MSIZE_Pos |
          (uint32_t)init->dstBurstDataItemsNum << AHBDMA_CR_DST_MSIZE_Pos |
          (uint32_t)init->srcGatherEn << AHBDMA_CR_SRC_GATHER_EN_Pos |
          (uint32_t)init->dstScatterEn << AHBDMA_CR_DST_SCATTER_EN_Pos |
          (uint32_t)init->tfrType << AHBDMA_CR_TT_FC_Pos |
          (uint32_t)dstLLPEnStatus << AHBDMA_CR_LLP_DST_EN_Pos |
          (uint32_t)srcLLPEnStatus << AHBDMA_CR_LLP_SRC_EN_Pos;
    lli->CTL_L = reg;

    reg = 0;
    reg = (uint32_t)init->blkTfrSize << (AHBDMA_CR_BLOCK_TS_Pos - AHBDMA_REG_WIDCH) |
          (uint32_t)init->wbDoneEn << (AHBDMA_CR_DONE_Pos - AHBDMA_REG_WIDCH);
    lli->CTL_H = reg;
}

/**
 * @brief Get default settings for LLI M2M mode
 *
 * @param init: LLI initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_LLI_M2MDefaultSet(AHBDMA_LLI_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                           uint32_t size, ControlStatus srcLLIUpdate, ControlStatus dstLLIUpdate)
{
    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_8;
    init->dstTrWidth = AHBDMA_BITS_8;

    init->srcAddressInc = AHBDMA_INCREMENTAL;
    init->dstAddressInc = AHBDMA_INCREMENTAL;

    if ((size >= 1) && (size <= 3))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
    }
    else if ((size >= 4) && (size <= 7))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_4;
    }
    else if ((size >= 8) && (size <= 15))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_8;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_8;
    }
    else if ((size >= 16) && (size <= 31))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_16;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_16;
    }
    else if ((size >= 32) && (size <= 63))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_32;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_32;
    }
    else if ((size >= 64) && (size <= 127))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_64;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_64;
    }
    else if ((size >= 128) && (size <= 255))
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_128;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_128;
    }
    else
    {
        init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_256;
        init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_256;
    }

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_MEM_TO_MEM;
    init->dstLLPEn     = dstLLIUpdate;
    init->srcLLPEn     = srcLLIUpdate;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = DISABLE;

    return DRV_OK;
}

/**
 * @brief Get default settings for LLI M2P mode
 *
 * @param init: LLI initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_LLI_M2PDefaultSet(AHBDMA_LLI_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                           uint32_t size, ControlStatus srcLLIUpdate, ControlStatus dstLLIUpdate)
{
    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_32;
    init->dstTrWidth = AHBDMA_BITS_32;

    init->srcAddressInc = AHBDMA_INCREMENTAL;
    init->dstAddressInc = AHBDMA_FIXED;

    init->srcBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;
    init->dstBurstDataItemsNum = AHBDMA_BURST_DATA_ITEMS_1;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_MEM_TO_PER;
    init->dstLLPEn     = dstLLIUpdate;
    init->srcLLPEn     = srcLLIUpdate;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = ENABLE;

    return DRV_OK;
}

/**
 * @brief Get default settings for LLI P2M mode
 *
 * @param init: LLI initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_LLI_P2MDefaultSet(AHBDMA_LLI_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                           uint32_t size, ControlStatus srcLLIUpdate, ControlStatus dstLLIUpdate)
{
    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_16;
    init->dstTrWidth = AHBDMA_BITS_16;

    init->srcAddressInc = AHBDMA_FIXED;
    init->dstAddressInc = AHBDMA_INCREMENTAL;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_PER_TO_MEM;
    init->dstLLPEn     = dstLLIUpdate;
    init->srcLLPEn     = srcLLIUpdate;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = ENABLE;

    return DRV_OK;
}

/**
 * @brief Get default settings for LLI P2P mode
 *
 * @param init: LLI initialized parameter structure
 * @param srcAddress: source peripheral address
 * @param dstAddress: destionation peripheral address
 * @param size: transfer size for single block
 * @return DRV_StatusTypeDef
 * DRV_OK: success
 * DRV_PARAM_ERR: Fail because of transfer size is greater than the maximum or is zero
 */
DRV_StatusTypeDef AHBDMA_LLI_P2PDefaultSet(AHBDMA_LLI_Init_TypeDef *init, uint32_t srcAddress, uint32_t dstAddress,
                                           uint32_t size, ControlStatus srcLLIUpdate, ControlStatus dstLLIUpdate)
{
    if ((size > AHBDMA_MAX_BLOCK_TR_SIZE) || (size == 0U))
    {
        return DRV_PARAM_ERR;
    }

    init->sar = (uint32_t)srcAddress;
    init->dar = (uint32_t)dstAddress;

    init->srcTrWidth = AHBDMA_BITS_32;
    init->dstTrWidth = AHBDMA_BITS_32;

    init->srcAddressInc = AHBDMA_FIXED;
    init->dstAddressInc = AHBDMA_FIXED;

    init->srcGatherEn  = DISABLE;
    init->dstScatterEn = DISABLE;
    init->tfrType      = AHBDMA_PER_TO_PER;
    init->dstLLPEn     = dstLLIUpdate;
    init->srcLLPEn     = srcLLIUpdate;
    init->blkTfrSize   = (uint16_t)size;
    init->wbDoneEn     = ENABLE;

    return DRV_OK;
}

/**
 * @brief Enable AHBDMAx interrupt request for channel [ch]
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @param ITMasks: DMA interrupt request masks
 */
void AHBDMA_ChITEnable(AHBDMA_TypeDef *AHBDMAx, uint32_t ch, uint32_t ITMasks)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));
    assert_param(IS_AHBDMA_ITMASK(ITMasks));

    if ((ITMasks & AHBDMA_IT_TFR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKTFR, AHBDMA_CH_IT_WE_ENABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_BLOCK_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKBLOCK, AHBDMA_CH_IT_WE_ENABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_SRCTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKSRCTRAN, AHBDMA_CH_IT_WE_ENABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_DSTTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKDSTTRAN, AHBDMA_CH_IT_WE_ENABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_ERR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKERR, AHBDMA_CH_IT_WE_ENABLE(ch));
    }

    SET_BIT(AHBDMAx->CH[ch].CTL, AHBDMA_CR_INT_EN_Msk);
}

/**
 * @brief Disable AHBDMAx interrupt request for channel [ch]
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel
 * @param ITMasks: DMA interrupt request masks
 */
void AHBDMA_ChITDisable(AHBDMA_TypeDef *AHBDMAx, uint32_t ch, uint32_t ITMasks)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));
    assert_param(IS_AHBDMA_ITMASK(ITMasks));

    if ((ITMasks & AHBDMA_IT_TFR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKTFR, AHBDMA_CH_IT_WE_DISABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_BLOCK_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKBLOCK, AHBDMA_CH_IT_WE_DISABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_SRCTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKSRCTRAN, AHBDMA_CH_IT_WE_DISABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_DSTTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKDSTTRAN, AHBDMA_CH_IT_WE_DISABLE(ch));
    }
    if ((ITMasks & AHBDMA_IT_ERR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.MASKERR, AHBDMA_CH_IT_WE_DISABLE(ch));
    }

    CLEAR_BIT(AHBDMAx->CH[ch].CTL, AHBDMA_CR_INT_EN_Msk);
}

/**
 * @brief Get channels that have transfer complete interrupt request
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * channel ID masks: The channel ID masks in transfer complete interrupt
 */
uint32_t AHBDMA_TfrITChMaskGet(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t ch;
    uint32_t ch_masks = 0;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (ch = 0; ch < AHBDMA_NUM_CHANNELS; ch++)
    {
        if ((READ_REG(AHBDMAx->INT.STATUSTFR) & AHBDMA_CH_IT_ACTIVE(ch)) != 0)
        {
            ch_masks |= BIT_MASK(ch);
        }
    }
    return ch_masks;
}

/**
 * @brief Get channels that have block transfer complete interrupt request
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * channel ID masks: The channel ID masks in block transfer complete interrupt
 */
uint32_t AHBDMA_BlockITChMaskGet(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t ch;
    uint32_t ch_masks = 0;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (ch = 0; ch < AHBDMA_NUM_CHANNELS; ch++)
    {
        if ((READ_REG(AHBDMAx->INT.STATUSBLOCK) & AHBDMA_CH_IT_ACTIVE(ch)) != 0)
        {
            ch_masks |= BIT_MASK(ch);
        }
    }
    return ch_masks;
}

/**
 * @brief Get channels that have source transfer complete interrupt request
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * channel ID masks: The channel ID masks in source transfer complete interrupt
 */
uint32_t AHBDMA_SrctranITChMaskGet(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t ch;
    uint32_t ch_masks = 0;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (ch = 0; ch < AHBDMA_NUM_CHANNELS; ch++)
    {
        if ((READ_REG(AHBDMAx->INT.STATUSSRCTRAN) & AHBDMA_CH_IT_ACTIVE(ch)) != 0)
        {
            ch_masks |= BIT_MASK(ch);
        }
    }
    return ch_masks;
}

/**
 * @brief  Get channels that have destionation transfer complete interrupt request
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * channel ID masks: The channel ID masks in destionation transfer complete interrupt
 */
uint32_t AHBDMA_DsttranITChMaskGet(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t ch;
    uint32_t ch_masks = 0;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (ch = 0; ch < AHBDMA_NUM_CHANNELS; ch++)
    {
        if ((READ_REG(AHBDMAx->INT.STATUSDSTTRAN) & AHBDMA_CH_IT_ACTIVE(ch)) != 0)
        {
            ch_masks |= BIT_MASK(ch);
        }
    }
    return ch_masks;
}

/**
 * @brief Get channels that have transfer error interrupt request
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @return uint32_t
 * channel ID masks: The channel ID masks in error transfer complete interrupt
 */
uint32_t AHBDMA_ErrITChMaskGet(AHBDMA_TypeDef *AHBDMAx)
{
    uint32_t ch;
    uint32_t ch_masks = 0;

    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));

    for (ch = 0; ch < AHBDMA_NUM_CHANNELS; ch++)
    {
        if ((READ_REG(AHBDMAx->INT.STATUSERR) & AHBDMA_CH_IT_ACTIVE(ch)) != 0)
        {
            ch_masks |= BIT_MASK(ch);
        }
    }
    return ch_masks;
}

/**
 * @brief Clear AHBDMAx interrupt request for channel [ch]
 *
 * @param AHBDMAx: AHBDMA peripheral address
 * @param ch: AHBDMA channel ID
 * @param ITMasks: DMA interrupt request masks
 */
void AHBDMA_ChITClear(AHBDMA_TypeDef *AHBDMAx, uint32_t ch, uint32_t ITMasks)
{
    assert_param(IS_AHBDMA_PERIPHERAL(AHBDMAx));
    assert_param(IS_AHBDMA_CHANNEL(ch));
    assert_param(IS_AHBDMA_ITMASK(ITMasks));

    if ((ITMasks & AHBDMA_IT_TFR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.CLEARTFR, AHBDMA_CH_IT_CLEAR(ch));
    }
    if ((ITMasks & AHBDMA_IT_BLOCK_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.CLEARBLOCK, AHBDMA_CH_IT_CLEAR(ch));
    }
    if ((ITMasks & AHBDMA_IT_SRCTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.CLEARSRCTRAN, AHBDMA_CH_IT_CLEAR(ch));
    }
    if ((ITMasks & AHBDMA_IT_DSTTRAN_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.CLEARDSTTRAN, AHBDMA_CH_IT_CLEAR(ch));
    }
    if ((ITMasks & AHBDMA_IT_ERR_MASK) != 0)
    {
        WRITE_REG(AHBDMAx->INT.CLEARERR, AHBDMA_CH_IT_CLEAR(ch));
    }
}

/************************ (C) COPYRIGHT ETMCU *****END OF FILE****/
